﻿using System;
using System.Collections.Generic;
using FizzBuzz.OutputProviders;
using NUnit.Framework;
using Rhino.Mocks;

namespace FizzBuzz.Tests
{
    [TestFixture]
    public class FizzBuzzTestFixture
    {
        [Test]
        public void should_fail_when_passing_a_divisor_with_a_value_zero()
        {
            var fizz = new FizzBuzzLogic(null);

            var lowerRange = 1;
            var upperRange = 100;
            var divisors = new List<Divisor>
                               {
                                   new Divisor{Value = 0,Text="Fizz"},
                                   new Divisor{Value = 5,Text="Buzz"},
                               };

            var actual = fizz.CalculateValues(lowerRange, upperRange, divisors);

            Assert.That(actual, Is.False);
        }

        [Test]
        public void should_fail_with_null_output_provider()
        {
            var fizz = new FizzBuzzLogic(null);

            var lowerRange = 1;
            var upperRange = 100;
            var divisors = new List<Divisor>();

            var actual = fizz.CalculateValues(lowerRange, upperRange, divisors);

            Assert.That(actual,Is.False);
        }

        [Test]
        public void should_fail_when_No_divisors_are_passed()
        {
            var mockProvider = MockRepository.GenerateMock<IOutputProvider>();

            var fizz = new FizzBuzzLogic(mockProvider);

            var lowerRange = 1;
            var upperRange = 100;
            var divisors = new List<Divisor>();

            var actual = fizz.CalculateValues(lowerRange, upperRange, divisors);

            Assert.That(actual,Is.False);
        }

        [Test]
        public void should_fail_when_passed_an_invalid_number_range()
        {
            var mockProvider = MockRepository.GenerateMock<IOutputProvider>();
            var fizz = new FizzBuzzLogic(mockProvider);

            var result = fizz.CalculateValues(10, 1,
                                              new[]
                                                  {
                                                      new Divisor {Value = 3, Text = "Fizz"},
                                                      new Divisor {Value = 5, Text = "Buzz"}
                                                  });

            Assert.IsFalse(result);
        }

        [Test]
        public void can_pass_4_divisors_with_success()
        {
            var resultList = new Dictionary<int, string>();
            var mockProvider = MockRepository.GenerateMock<IOutputProvider>();

            mockProvider
                .Expect(x => x.Render(0, ""))
                .IgnoreArguments()
                .WhenCalled(x => resultList.Add(Convert.ToInt32(x.Arguments[0]), x.Arguments[1].ToString()));


            var fizz = new FizzBuzzLogic(mockProvider);

            var lowerRange = 1;
            var upperRange = 100;
            var divisors = new[]
                               {
                                   new Divisor { Value = 3, Text = "Three" }, 
                                   new Divisor { Value = 5, Text = "Five" },
                                   new Divisor { Value = 10, Text = "Ten" },
                                   new Divisor { Value = 15, Text = "Fifteen" }
                               };

            var actual = fizz.CalculateValues(lowerRange, upperRange, divisors);

            Assert.That(actual, Is.True);
            Assert.That(resultList.Count, Is.EqualTo(100));

            foreach (var item in resultList)
            {
                Console.WriteLine(resultList[item.Key]);
            }

            mockProvider.VerifyAllExpectations();
        }

        [Test]
        public void can_pass_2_divisors_with_success()
        {
            var resultList = new Dictionary<int, string>();
            var mockProvider = MockRepository.GenerateMock<IOutputProvider>();

            mockProvider
                .Expect(x => x.Render(0, ""))
                .IgnoreArguments()
                .WhenCalled(x => resultList.Add(Convert.ToInt32(x.Arguments[0]), x.Arguments[1].ToString()));


            var fizz = new FizzBuzzLogic(mockProvider);

            var lowerRange = 1;
            var upperRange = 15;
            var divisors = new[] {new Divisor {Value = 3, Text = "Fizz"}, new Divisor {Value = 5, Text = "Buzz"}};
            var actual = fizz.CalculateValues(lowerRange, upperRange, divisors);

            Assert.That(actual, Is.True);
            Assert.That(resultList.Count, Is.EqualTo(15));

            foreach (var item in resultList)
            {
                Console.WriteLine(resultList[item.Key]);
            }

            mockProvider.VerifyAllExpectations();
        }

        [Test]
        public void can_run_fizz_buzz_with_range_of_numbers_with_success()
        {
            var resultList = new Dictionary<int, string>();
            var mockProvider = MockRepository.GenerateMock<IOutputProvider>();

            mockProvider
                .Expect(x => x.Render(0, ""))
                .IgnoreArguments()
                .WhenCalled(x => resultList.Add(Convert.ToInt32(x.Arguments[0]), x.Arguments[1].ToString()));


            var fizz = new FizzBuzzLogic(mockProvider);

            var lowerRange = 1;
            var upperRange = 10;

            var actual = fizz.CalculateValues(lowerRange, upperRange,
                                             new[]
                                                 {
                                                     new Divisor {Value = 3, Text = "Fizz"},
                                                     new Divisor {Value = 5, Text = "Buzz"}
                                                 });

            Assert.That(actual, Is.True);
            Assert.That(resultList.Count, Is.EqualTo(10));

            mockProvider.VerifyAllExpectations();
        }

        [Test]
        public void baseline_can_run_fizz_buzz_with_success()
        {
            var resultList = new Dictionary<int, string>();
            var mockProvider = MockRepository.GenerateMock<IOutputProvider>();

            mockProvider
                .Expect(x => x.Render(0, ""))
                .IgnoreArguments()
                .WhenCalled(x => resultList.Add(Convert.ToInt32(x.Arguments[0]), x.Arguments[1].ToString()));


            var fizz = new FizzBuzzLogic(mockProvider);


            var actual = fizz.CalculateValues();

            Assert.That(actual, Is.True);
            Assert.That(resultList.Count, Is.EqualTo(100));
            mockProvider.VerifyAllExpectations();
        }
    }
}